#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>

#define MICRO_PER_SECOND 1000000

long int smooth(long int **camada, long int altura, long int largura, int pos_altura, int pos_largura){     
     int i,j;
     long int valor = 0;
     for(i=pos_altura-2; i<=pos_altura+2; i++){     
         for(j=pos_largura-2; j<=pos_largura+2; j++){
             if(i<0 || j<0 || i>=altura || j>=largura)                   
                    valor += 0;                          
             else valor += camada[i][j];
         }            
     }  
     valor = valor / 25;    
     return valor;
}

int main(int argc, char *argv[]){
    
    FILE *arquivo_inicial,*arquivo_final;                    
    unsigned char cabecalho_antes[18];      
    unsigned char cabecalho_depois[28];     
    int i,j;
    
    long int largura = 0, altura = 0;                  
    long int **vermelho, **verde, **azul, **smooth_vermelho, **smooth_verde, **smooth_azul;           
    
    struct timeval tempo_inicial;
    struct timeval tempo_final;
    gettimeofday( &tempo_inicial, NULL ); 
	
    arquivo_inicial = fopen(argv[1],"r+b");
    if(arquivo_inicial == NULL)
       printf("Erro ao abrir o arquivo...\n");
    
    else{
	rewind(arquivo_inicial);
	
	for(i=0;i<18;i++)
	   fread(&cabecalho_antes[i],sizeof(unsigned char),1,arquivo_inicial);  
	fread(&largura,sizeof(unsigned char),4,arquivo_inicial);  
	fread(&altura,sizeof(unsigned char),4,arquivo_inicial);  
	for(i=0;i<28;i++)
	   fread(&cabecalho_depois[i],1,1,arquivo_inicial);  
	   
	vermelho = (long int **) malloc (altura * sizeof(long int *));
	verde = (long int **) malloc (altura * sizeof(long int *));
	azul = (long int **) malloc (altura * sizeof(long int *));
	for ( i = 0; i < altura; i++ ){
	   vermelho[i] = (long int*) malloc (largura* sizeof(long int)); 
	   verde[i] = (long int*) malloc (largura* sizeof(long int));
	   azul[i] = (long int*) malloc (largura* sizeof(long int));
	}		   
	
	for(i=0;i<altura;i++){
	   for(j=0;j<largura;j++){								
		   vermelho[i][j] = 0;
		   verde[i][j] = 0;
		   azul[i][j] = 0;
		   
		   fread(&vermelho[i][j],1,1,arquivo_inicial);  
		   fread(&verde[i][j],1,1,arquivo_inicial);
		   fread(&azul[i][j],1,1,arquivo_inicial);
	   } 
	}
	
	smooth_vermelho = (long int **) malloc (altura * sizeof(long int *));
	smooth_verde = (long int **) malloc (altura * sizeof(long int *));
	smooth_azul = (long int **) malloc (altura * sizeof(long int *));
	
	for ( i = 0; i < altura; i++ ){
	   smooth_vermelho[i] = (long int*) malloc (largura* sizeof(long int)); 
	   smooth_verde[i] = (long int*) malloc (largura* sizeof(long int));
	   smooth_azul[i] = (long int*) malloc (largura* sizeof(long int)); 
	}
	 

	for(i=0;i<altura;i++){
	   for(j=0;j<largura;j++){
		   smooth_vermelho[i][j] = smooth(vermelho,altura,largura,i,j); 
		   smooth_verde[i][j] = smooth(verde,altura,largura,i,j);
		   smooth_azul[i][j] = smooth(azul,altura,largura,i,j);
		   
	   } 
	}    
	
	arquivo_final = fopen(argv[2],"wb+");
	for(i=0;i<18;i++)
	   fwrite(&cabecalho_antes[i],sizeof(unsigned char),1,arquivo_final);  
	fwrite(&largura,sizeof(unsigned char),4,arquivo_final);  
	fwrite(&altura,sizeof(unsigned char),4,arquivo_final);  
	for(i=0;i<28;i++)
	   fwrite(&cabecalho_depois[i],1,1,arquivo_final);
	   
	for(i=0;i<altura;i++){
	   for(j=0;j<largura;j++){
		   
		   fwrite(&smooth_vermelho[i][j],1,1,arquivo_final);  
		   fwrite(&smooth_verde[i][j],1,1,arquivo_final);
		   fwrite(&smooth_azul[i][j],1,1,arquivo_final);
		  
	   } 
	}   		
	free(vermelho);
	free(verde);
	free(azul);
	free(smooth_vermelho);
	free(smooth_verde);
	free(smooth_azul);
	fclose(arquivo_final);   
    }
    fclose(arquivo_inicial);
   
    gettimeofday( &tempo_final, NULL ); 
    printf("\nTempo de processamento Sequencial: %d milisegundos.\n\n", (int) (1000 * (tempo_final.tv_sec - tempo_inicial.tv_sec) + (tempo_final.tv_usec - tempo_inicial.tv_usec) / 1000));
    
    return 0;
}
